package com.yami.shop.manager.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.yami.shop.bean.app.dto.*;
import com.yami.shop.bean.bo.PlatformCommissionOrderItemBO;
import com.yami.shop.bean.enums.DvyType;
import com.yami.shop.bean.enums.OrderType;
import com.yami.shop.bean.enums.ProdType;
import com.yami.shop.bean.model.Category;
import com.yami.shop.bean.model.Product;
import com.yami.shop.bean.vo.ShopTransFeeVO;
import com.yami.shop.bean.vo.UserDeliveryInfoVO;
import com.yami.shop.bean.vo.VirtualRemarkVO;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.constants.CacheNames;
import com.yami.shop.common.constants.OrderCacheNames;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.CacheManagerUtil;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.service.CategoryService;
import com.yami.shop.common.util.BeanUtil;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 确认订单适配
 *
 * @author FrozenWatermelon
 * @date 2020/12/07
 */
@Component
@AllArgsConstructor
public class ConfirmOrderManager {

    private final CacheManagerUtil cacheManagerUtil;

    private final CategoryService categoryService;

    /**
     * 过滤物流不同的商品
     *
     * @param dbShopCartItems 用户选择的商品项
     * @return 返回过滤掉的商品项item
     */
    public List<ShopCartItemDto> filterShopItemsByType(ShopCartOrderMergerDto shopCartOrderMerger, List<ShopCartItemDto> dbShopCartItems) {
        if (CollUtil.isEmpty(dbShopCartItems)) {
            return new ArrayList<>();
        }
        Integer dvyType = shopCartOrderMerger.getDvyType();
        List<ShopCartItemDto> shopCartItems = new ArrayList<>();
        Set<ShopCartItemDto> devSet = new HashSet<>();
        for (ShopCartItemDto shopCartItem : dbShopCartItems) {
            if (Objects.isNull(shopCartItem.getComboId())) {
                shopCartItem.setComboId(0L);
            }
            // 没有配置物流配送类型为无需配送，移除该订单项(非虚商品，虚拟商品不需要判断配送类型)
            if (shopCartItem.getMold() == 0 && !deliverable(dvyType, shopCartItem)) {
                continue;
            }
            // 添加到可配送列表
            devSet.add(shopCartItem);
        }
        Map<Long, List<ShopCartItemDto>> shopCartItemMap = new HashMap<>();

        for (ShopCartItemDto shopCartItem : dbShopCartItems) {
            // 普通商品直接处理了
            if (Objects.equals(shopCartItem.getComboId(), 0L)) {
                // 活动商品购买且不属于套餐活动
                if (Objects.equals(shopCartItem.getProdType(), ProdType.PROD_TYPE_ACTIVE.value())) {
                    // 活动商品不能单独购买
                    throw new YamiShopBindException("yami.active.prod.cannot.buy");
                }
                if (devSet.contains(shopCartItem)) {
                    shopCartItems.add(shopCartItem);
                }
                continue;
            }
            // 在商品详情也直接提交的套餐订单，没有购物车id，也仅有一个套餐
            boolean confirmCombo = Objects.isNull(shopCartItem.getBasketId()) || shopCartItem.getBasketId() <= 0 && devSet.containsAll(dbShopCartItems);
            if (confirmCombo) {
                // 可配送列表中是否包含整个套餐，套餐是一个整体，只判断一次就行了
                if (devSet.containsAll(dbShopCartItems)) {
                    shopCartItems.addAll(dbShopCartItems);
                }
                break;
            }
            // 套餐商品分组
            Long mainBasketId = shopCartItem.getBasketId();
            if (!Objects.equals(shopCartItem.getParentBasketId(), 0L)) {
                mainBasketId = shopCartItem.getParentBasketId();
            }
            List<ShopCartItemDto> shopCartItemList = shopCartItemMap.get(mainBasketId);
            if (Objects.isNull(shopCartItemList)) {
                shopCartItemList = new ArrayList<>();
                shopCartItemMap.put(mainBasketId, shopCartItemList);
            }
            shopCartItemList.add(shopCartItem);
        }

        for (Long basketId : shopCartItemMap.keySet()) {
            List<ShopCartItemDto> shopCartItemList = shopCartItemMap.get(basketId);
            // 套餐是一个整体，需要套餐中所有的商品都是可配送才能添加到订单列表
            if (devSet.containsAll(shopCartItemList)) {
                shopCartItems.addAll(shopCartItemList);
            }
        }
        // 获取过滤掉的商品项
        if (CollUtil.isNotEmpty(shopCartItems) && !Objects.equals(dbShopCartItems.size(), shopCartItemMap.size())) {
//            dbShopCartItems.removeAll(shopCartItems);
            shopCartOrderMerger.setFilterShopItems(dbShopCartItems);
        } else {
            shopCartOrderMerger.setFilterShopItems(new ArrayList<>());
        }
        return shopCartItems;
    }

    private boolean deliverable(Integer dvyType, ShopCartItemDto shopCartItem) {
        Product.DeliveryModeVO deliveryModeVO = shopCartItem.getDeliveryModeVO();
        boolean hasShopDelivery = deliveryModeVO.getHasShopDelivery() != null && Objects.equals(dvyType, DvyType.DELIVERY.value()) && deliveryModeVO.getHasShopDelivery();
        boolean hasUserPickUp = deliveryModeVO.getHasUserPickUp() != null && Objects.equals(dvyType, DvyType.STATION.value()) && deliveryModeVO.getHasUserPickUp();
        boolean hasCityDelivery = deliveryModeVO.getHasCityDelivery() != null && Objects.equals(dvyType, DvyType.SAME_CITY.value()) && deliveryModeVO.getHasCityDelivery();
        if (hasShopDelivery || hasUserPickUp || hasCityDelivery) {
            return true;
        }
        return false;
    }


    /**
     * 店铺营销活动计算完成后重算一次订单金额
     */
    public void recalculateAmountWhenFinishingCalculateShop(ShopCartOrderMergerDto shopCartOrderMerger, List<ShopCartDto> shopCarts, UserDeliveryInfoVO userDeliveryInfo) {
        Map<Long, ShopTransFeeVO> shopIdWithShopTransFee = userDeliveryInfo.getShopIdWithShopTransFee();

        // 所有店铺的订单信息
        List<ShopCartOrderDto> shopCartOrders = new ArrayList<>();

        double actualTotal = 0;
        double total = 0;
        int totalCount = 0;
        double allOrderReduce = 0;
        double totalTransFee = 0;
        long scoreTotal = 0;

        // 所有店铺所有的商品item
        for (ShopCartDto shopCart : shopCarts) {
            // 每个店铺的订单信息
            ShopCartOrderDto shopCartOrder = new ShopCartOrderDto();
            shopCartOrder.setOrderType(shopCartOrderMerger.getOrderType().value());
            shopCartOrder.setShopId(shopCart.getShopId());
            shopCartOrder.setShopName(shopCart.getShopName());
            shopCartOrder.setShopReduce(shopCart.getShopReduce());
            total = Arith.add(shopCart.getTotal(), total);
            totalCount += shopCart.getTotalCount();
            allOrderReduce = Arith.add(allOrderReduce, shopCart.getShopReduce());

            // 如果某家店因为各种优惠活动满减，使得金额变为负数，则这家店最低应该支付一分钱，而里面最贵的那件商品，也是支付一分钱，优惠金额 = （商品金额 - 一分钱）
            if (shopCart.getActualTotal() < 0.01 && !Objects.equals(shopCart.getShopId(), Constant.PLATFORM_SHOP_ID)) {
                shopCartOrder.setActualTotal(0.01);
                shopCartOrder.setShopReduce(Arith.sub(shopCart.getTotal(), 0.01));

                List<ShopCartItemDto> shopCartShopCartItem = getShopShopCartItem(shopCart.getShopCartItemDiscounts());
                resetActualTotal(shopCartShopCartItem);
            }
            // 店铺优惠金额 = 优惠金额
            shopCartOrder.setShopReduce(shopCartOrder.getShopReduce());

            // 要计算运费
            totalTransFee = calculateTransFee(shopIdWithShopTransFee, totalTransFee, shopCart, shopCartOrder);

            // 店铺优惠券优惠金额
            shopCartOrder.setCouponReduce(shopCart.getCouponReduce());
            shopCartOrder.setShopComboAmount(shopCart.getComboReduce());
            shopCartOrder.setShopCartItemDiscounts(shopCart.getShopCartItemDiscounts());
            shopCartOrder.setCoupons(shopCart.getCoupons());
            shopCartOrder.setTotal(shopCart.getTotal());
            shopCartOrder.setTotalCount(shopCart.getTotalCount());
            actualTotal = Arith.add(actualTotal, shopCartOrder.getActualTotal());
            if (Objects.equals(shopCartOrderMerger.getOrderType(), OrderType.SCORE)) {
                // 积分订单使用积分
                shopCartOrder.setUseScore(shopCart.getScoreTotal());
            } else {
                shopCartOrder.setUseScore(shopCartOrderMerger.getUsableScore());
            }
            shopCartOrder.setDiscountReduce(shopCart.getDiscountReduce());
            shopCartOrders.add(shopCartOrder);
            scoreTotal += shopCart.getScoreTotal();
        }

        shopCartOrderMerger.setActualTotal(actualTotal);
        shopCartOrderMerger.setTotal(total);
        shopCartOrderMerger.setTotalCount(totalCount);
        shopCartOrderMerger.setOrderReduce(allOrderReduce);
        shopCartOrderMerger.setTotalTransFee(totalTransFee);
        shopCartOrderMerger.setShopCartOrders(shopCartOrders);
        shopCartOrderMerger.setOrderSelfStationList(userDeliveryInfo.getOrderSelfStation());
        shopCartOrderMerger.setUserAddr(BeanUtil.map(userDeliveryInfo.getUserAddr(), UserAddrDto.class));
        shopCartOrderMerger.setShopCityStatus(userDeliveryInfo.getShopCityStatus());
        shopCartOrderMerger.setFreeTransFee(userDeliveryInfo.getTotalFreeTransFee());
        shopCartOrderMerger.setStartDeliveryFee(userDeliveryInfo.getStartDeliveryFee());
        if (Objects.equals(shopCartOrderMerger.getOrderType(), OrderType.SCORE)) {
            shopCartOrderMerger.setUsableScore(scoreTotal);
        }
    }

    private double calculateTransFee(Map<Long, ShopTransFeeVO> shopIdWithShopTransFee, double totalTransFee, ShopCartDto shopCart, ShopCartOrderDto shopCartOrder) {
        if (shopIdWithShopTransFee != null) {
            ShopTransFeeVO shopTransFeeVO = shopIdWithShopTransFee.get(shopCartOrder.getShopId());

            // 店铺的实付 = 购物车实付 + 运费
            shopCartOrder.setActualTotal(shopCart.getActualTotal() + shopTransFeeVO.getTransFee());
            // 运费
            shopCartOrder.setTransFee(shopTransFeeVO.getTransFee());
            shopCartOrder.setFreeTransFee(shopTransFeeVO.getFreeTransFee());
            totalTransFee = Arith.add(totalTransFee, shopTransFeeVO.getTransFee());
        } else {
            // 运费
            shopCartOrder.setTransFee(0.0);
            shopCartOrder.setFreeTransFee(0.0);
            // 店铺的实付 = 购物车实付 + 运费
            shopCartOrder.setActualTotal(Arith.add(shopCart.getActualTotal(), shopCartOrder.getTransFee()));
        }
        return totalTransFee;
    }

    /**
     * 获取店铺下的所有订单
     */
    private List<ShopCartItemDto> getShopShopCartItem(List<ShopCartItemDiscountDto> shopCartItemDiscounts) {
        List<ShopCartItemDto> shopCartItemList = new ArrayList<>();
        for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartItemDiscounts) {
            shopCartItemList.addAll(shopCartItemDiscount.getShopCartItems());
        }
        shopCartItemList.sort(Comparator.comparingDouble(ShopCartItemDto::getActualTotal));
        return shopCartItemList;
    }


    /**
     * 重新计算金额，避免订单无法支付
     */
    private void resetActualTotal(List<ShopCartItemDto> shopCartShopCartItem) {
        Iterator<ShopCartItemDto> iterator = shopCartShopCartItem.iterator();
        while (iterator.hasNext()) {
            ShopCartItemDto shopCartItem = iterator.next();
            shopCartItem.setShareReduce(Arith.add(shopCartItem.getShareReduce(), shopCartItem.getPlatformShareReduce()));
            shopCartItem.setActualTotal(Arith.sub(shopCartItem.getProductTotalAmount(), shopCartItem.getShareReduce()));
            if (iterator.hasNext()) {
                shopCartItem.setActualTotal(0.0);
                shopCartItem.setShareReduce(shopCartItem.getProductTotalAmount());
            } else {
                shopCartItem.setActualTotal(0.01);
                shopCartItem.setShareReduce(shopCartItem.getProductTotalAmount() - 0.01);
            }
        }
    }

    /**
     * 结束平台优惠的计算之后，还要重算一遍金额
     */
    public void recalculateAmountWhenFinishingCalculatePlatform(ShopCartOrderMergerDto shopCartOrderMergerDto) {
        List<VirtualRemarkVO> virtualRemarkList = new ArrayList<>();

        List<ShopCartOrderDto> shopCartOrders = shopCartOrderMergerDto.getShopCartOrders();
        List<ShopCartItemDto> allShopCartItem = new ArrayList<>();

        // 所有订单实际金额
        double actualTotal = 0.00;
        // 所有订单优惠金额
        double allOrderReduce = 0.00;
        double totalTransFee = 0.00;
        double totalShopFreeTransFee = 0.00;
        for (ShopCartOrderDto shopCartOrder : shopCartOrders) {

            // 订单实际金额
            double orderActualTotal = 0.00;
            // 商家优惠金额
            double orderReduceAmount = 0.00;
            // 商家满减优惠金额
            double couponAmount = 0.00;
            // 商家优惠券优惠金额
            double discountAmount = 0.00;
            // 平台优惠券优惠金额
            double platformCouponAmount = 0.00;
            // 平台等级优惠金额
            double levelAmount = 0.00;
            // 商家优惠金额
            double orderPlatformAmount = 0.00;
            // 满减金额计算
            List<ShopCartItemDiscountDto> shopCartItemDiscounts = shopCartOrder.getShopCartItemDiscounts();
            for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartItemDiscounts) {
                List<ShopCartItemDto> shopCartItems = shopCartItemDiscount.getShopCartItems();
                allShopCartItem.addAll(shopCartItems);
                for (ShopCartItemDto shopCartItem : shopCartItems) {
                    shopCartItem.setPlatformShareReduce(Arith.roundByBanker(shopCartItem.getPlatformShareReduce(), 2));
                    shopCartItem.setShareReduce(Arith.add(Arith.roundByBanker(shopCartItem.getShareReduce(), 2), shopCartItem.getPlatformShareReduce()));
                    shopCartItem.setActualTotal(Arith.sub(shopCartItem.getProductTotalAmount(), shopCartItem.getShareReduce()));
                    orderActualTotal = Arith.add(orderActualTotal, shopCartItem.getActualTotal());
                    orderReduceAmount = Arith.add(orderReduceAmount, shopCartItem.getShareReduce());
                    orderPlatformAmount = Arith.addMayBeEmpty(orderPlatformAmount, shopCartItem.getPlatformShareReduce());
                    discountAmount = Arith.addMayBeEmpty(discountAmount, shopCartItem.getDiscountAmount());
                    couponAmount = Arith.addMayBeEmpty(couponAmount, shopCartItem.getShopCouponAmount());
                    platformCouponAmount = Arith.addMayBeEmpty(platformCouponAmount, shopCartItem.getPlatformCouponAmount());
                    levelAmount = Arith.addMayBeEmpty(levelAmount, shopCartItem.getLevelReduce());
                    if (CollectionUtil.isNotEmpty(shopCartItem.getVirtualRemarkList())) {
                        virtualRemarkList.addAll(shopCartItem.getVirtualRemarkList());
                    }
                }
            }
            shopCartOrder.setActualTotal(Arith.add(orderActualTotal, shopCartOrder.getTransFee()));
            // 放入优惠金额
            shopCartOrder.setShopReduce(orderReduceAmount);
            // 放入平台优惠金额,如果用户等级免自营店运费也要放进去
            shopCartOrder.setPlatformAmount(Arith.add(orderPlatformAmount, shopCartOrder.getPlatformFreeFreightAmount()));
            shopCartOrder.setCouponReduce(couponAmount);
            shopCartOrder.setDiscountReduce(discountAmount);
            shopCartOrder.setPlatformCouponReduce(platformCouponAmount);
            shopCartOrder.setLevelReduce(levelAmount);
            double shopActual = Arith.add(Arith.sub(shopCartOrder.getActualTotal(), shopCartOrder.getTransFee()), shopCartOrder.getFreeTransFee());
            // 如果是折扣特别小的情况下，导致实际金额为0，改变最小支付金额为0.01元,并且优惠金额减去0.01。
            if (shopActual < 0.01) {
                shopCartOrder.setActualTotal(Arith.add(shopCartOrder.getActualTotal(), 0.01));
                shopCartOrder.setPlatformAmount(Arith.sub(shopCartOrder.getPlatformAmount(), 0.01));
                shopCartOrder.setShopReduce(Arith.sub(shopCartOrder.getShopReduce(), 0.01));
                // 并且如果等级优惠金额不为空，则在等级优惠金额减去，否则减去平台优惠券的分摊金额
                if (shopCartOrderMergerDto.getTotalLevelAmount() > 0.00) {
                    shopCartOrderMergerDto.setTotalLevelAmount(Arith.sub(shopCartOrderMergerDto.getTotalLevelAmount(), 0.01));
                    shopCartOrder.setLevelReduce(Arith.sub(shopCartOrder.getLevelReduce(), 0.01));
                    // 按照抵扣金额大小排序，扣除最大的那个商品项的等级优惠金额0.01元
                    List<ShopCartItemDto> items = allShopCartItem.stream().sorted(Comparator.comparing(ShopCartItemDto::getLevelReduce).reversed()).collect(Collectors.toList());
                    ShopCartItemDto shopCartItemDto = items.get(0);
                    shopCartItemDto.setActualTotal(0.01);
                    shopCartItemDto.setPlatformShareReduce(Arith.sub(shopCartItemDto.getPlatformShareReduce(), 0.01));
                    shopCartItemDto.setShareReduce(Arith.sub(shopCartItemDto.getShareReduce(), 0.01));
                    shopCartItemDto.setLevelReduce(Arith.sub(shopCartItemDto.getLevelReduce(), 0.01));
                }
            }
            // 加上平台运费优惠金额
            shopCartOrder.setShopReduce(Arith.add(shopCartOrder.getShopReduce(),shopCartOrder.getPlatformFreeFreightAmount()));
            actualTotal = Arith.add(actualTotal, shopCartOrder.getActualTotal());
            allOrderReduce = Arith.add(allOrderReduce, shopCartOrder.getShopReduce());
            totalTransFee = Arith.add(totalTransFee, shopCartOrder.getTransFee());
            totalShopFreeTransFee = Arith.add(totalShopFreeTransFee, shopCartOrder.getFreeTransFee());
        }

        shopCartOrderMergerDto.setActualTotal(actualTotal);
        shopCartOrderMergerDto.setOrderReduce(allOrderReduce);
        shopCartOrderMergerDto.setTotalTransFee(totalTransFee);
        shopCartOrderMergerDto.setShopFreeTransFee(totalShopFreeTransFee);
        shopCartOrderMergerDto.setShopCartOrders(shopCartOrders);
        shopCartOrderMergerDto.setVirtualRemarkList(virtualRemarkList);
    }

    /**
     * 计算平台佣金，积分订单不可用
     */
    public void calculatePlatformCommission(ShopCartOrderMergerDto shopCartOrderMerger) {
        List<ShopCartOrderDto> shopCartOrders = shopCartOrderMerger.getShopCartOrders();
        for (ShopCartOrderDto shopCartOrder : shopCartOrders) {
            double platformCommission = 0.00;
            List<ShopCartItemDiscountDto> shopCartItemDiscounts = shopCartOrder.getShopCartItemDiscounts();
            for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartItemDiscounts) {
                List<ShopCartItemDto> shopCartItems = shopCartItemDiscount.getShopCartItems();
                List<PlatformCommissionOrderItemBO> platformCommissionShopCartItems = new ArrayList<>();
                for (ShopCartItemDto shopCartItem : shopCartItems) {
                    PlatformCommissionOrderItemBO platformCommissionOrderItem = new PlatformCommissionOrderItemBO();
                    platformCommissionOrderItem.setShopId(shopCartItem.getShopId());
                    platformCommissionOrderItem.setCategoryId(shopCartItem.getCategoryId());
                    platformCommissionOrderItem.setSkuId(shopCartItem.getSkuId());
                    platformCommissionShopCartItems.add(platformCommissionOrderItem);
                }
                // 获取整个平台的佣金比例
                List<Category> categoryRates = categoryService.listRate();
                List<PlatformCommissionOrderItemBO> data = categoryService.calculatePlatformCommission(platformCommissionShopCartItems, categoryRates);
                Map<Long, PlatformCommissionOrderItemBO> categoryMap = data.stream().collect(Collectors.toMap(PlatformCommissionOrderItemBO::getSkuId, p -> p));
                for (ShopCartItemDto shopCartItem : shopCartItems) {
                    PlatformCommissionOrderItemBO platformCommissionOrderItem = categoryMap.get(shopCartItem.getSkuId());
                    // 分摊比例
                    shopCartItem.setRate(platformCommissionOrderItem.getRate());
                    // 平台佣金 = （实付金额 + 平台优惠金额） * 比例 / 100
                    double itemPlatformCommission = Arith.roundByBanker(Arith.div(Arith.mul(Arith.add(shopCartItem.getActualTotal(), shopCartItem.getPlatformShareReduce()),
                            platformCommissionOrderItem.getRate()), 100), 2);
                    shopCartItem.setPlatformCommission(itemPlatformCommission);
                    platformCommission = Arith.add(platformCommission, itemPlatformCommission);
                }
            }
            shopCartOrder.setPlatformCommission(platformCommission);
        }
    }

    public void cacheCalculatedInfo(String userId, ShopCartOrderMergerDto shopCartOrderMerger) {
        // 防止重复提交
        RedisUtil.STRING_REDIS_TEMPLATE.opsForValue().set(OrderCacheNames.ORDER_CONFIRM_UUID_KEY + CacheNames.UNION + userId, String.valueOf(userId));
        // 保存订单计算结果缓存，省得重新计算 并且 用户确认的订单金额与提交的一致
        cacheManagerUtil.putCache(OrderCacheNames.ORDER_CONFIRM_KEY, String.valueOf(userId), shopCartOrderMerger);
    }
}
